package com.fenfen.novel.service;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;
import android.util.Log;

import com.fenfen.novel.R;
import com.fenfen.novel.db.NovelDBProvider;
import com.fenfen.novel.db.NovelDownInfo;
import com.fenfen.novel.db.NovelDownStatus;
import com.fenfen.novel.utils.CommonUtil;
import com.liulishuo.filedownloader.BaseDownloadTask;
import com.liulishuo.filedownloader.FileDownloader;
import com.liulishuo.filedownloader.model.FileDownloadStatus;
import com.liulishuo.filedownloader.notification.BaseNotificationItem;
import com.liulishuo.filedownloader.notification.FileDownloadNotificationHelper;
import com.liulishuo.filedownloader.notification.FileDownloadNotificationListener;
import com.liulishuo.filedownloader.util.FileDownloadHelper;

import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class NovelDownService extends Service {

  private static String Tag = NovelDownService.class.getSimpleName();


  private static Context context;

  private FileDownloadNotificationHelper<NotificationItem> notificationHelper;
  private NotificationListener downloadListener;

  private List<NovelDownInfo> downList = new ArrayList();

  @Nullable
  @Override
  public IBinder onBind(Intent intent) {
    return null;
  }

  @Override
  public void onCreate() {
    super.onCreate();
    context = NovelDownService.this;
    notificationHelper = new FileDownloadNotificationHelper<>();
    downloadListener = new NotificationListener(new WeakReference<>(this));

    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(KEY_PAUSE);
    intentFilter.addAction(KEY_REMOVE);
    intentFilter.addAction(KEY_START);
    intentFilter.addAction(KEY_COMPLETE);
    registerReceiver(controlReceiver, intentFilter);
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
    List<NovelDownInfo> dbList = NovelDBProvider.getInstance(this).getNovelsNotDown();
    if(dbList == null || dbList.size() == 0) {
      stopSelf();
      return Service.START_NOT_STICKY;
    }
    downList.clear();
    //no start service
    downList.addAll(dbList);
    for (NovelDownInfo list : downList) {
      int novelId = list.getNovelDownStatus().getNovelId();
      String url = CommonUtil.BASE_URL + novelId + ".txt";
      int taskId = FileDownloader.getImpl().create(url)
          .setPath(CommonUtil.getNovelFilePath(context, novelId))
          .setTag(novelId)
          .setTag(novelId, list.getNovelName())
          .setListener(downloadListener).start();
      if (taskId != 0) {
        downloadListener.addNotificationItem(taskId);
      }
    }
    return Service.START_STICKY;
  }

  public BroadcastReceiver controlReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
      if (intent.getAction().equals(KEY_PAUSE)) {
        int taskId = intent.getIntExtra(EXTRA_ID, 0);
        FileDownloader.getImpl().pause(taskId);
      } else if (intent.getAction().equals(KEY_START)) {
        int taskId = intent.getIntExtra(EXTRA_ID, 0);
        NotificationItem item = notificationHelper.get(taskId);
        int novelId = item.getNovelId();
        String novelName = item.getNovelName();
        String url = CommonUtil.BASE_URL + novelId + ".txt";

        int newTaskId = FileDownloader.getImpl().create(url)
            .setPath(CommonUtil.getNovelFilePath(context, novelId))
            .setTag(novelId)
            .setCallbackProgressMinInterval(1000 * 3)
            .setTag(novelId, novelName)
            .setListener(downloadListener).start();
        if (newTaskId != 0) {
          downloadListener.addNotificationItem(newTaskId);
        }
      } else if (intent.getAction().equals(KEY_REMOVE)) {
        int taskId = intent.getIntExtra(EXTRA_ID, 0);
        NotificationItem item = notificationHelper.get(taskId);
        int novelId = item.getNovelId();
        boolean result = NovelDBProvider.getInstance(context).removeDownRecord(novelId);
        if(!result) {
          CommonUtil.showToast(context, getString(R.string.remove_novel_download_error));
          return;
        }
        handleDownList(novelId);
        FileDownloader.getImpl().pause(taskId);
        notificationHelper.remove(taskId);
//        BaseDownloadTask task = FileDownloadList.getImpl().get(id);
        getNM().cancel(taskId);
        for(NovelDownInfo info : downList) {
          Log.d(Tag, "info.name=" + info.getNovelName());
        }
        if (downList != null && downList.size() == 0) {
          Intent service = new Intent(context, NovelDownService.class);
          stopService(service);
        }
      } else if (intent.getAction().equals(KEY_COMPLETE)) {
        int taskId = intent.getIntExtra(EXTRA_ID, 0);
        notificationHelper.remove(taskId);
        getNM().cancel(taskId);
        if (downList != null && downList.size() == 0) {
          Intent service = new Intent(context, NovelDownService.class);
          stopService(service);
        }
      }
    }
  };

  @Override
  public void onDestroy() {
    super.onDestroy();
    unregisterReceiver(controlReceiver);
    downList.clear();
    notificationHelper.clear();
    getNM().cancelAll();
  }

  private NotificationManager getNM() {
    return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
  }

  public class NotificationItem extends BaseNotificationItem {

    private int novelId;
    private String novelName;

    private NotificationCompat.Builder builder;

    public NotificationCompat.Builder getBuilder() {
      return builder;
    }

    public void setBuilder(NotificationCompat.Builder builder) {
      this.builder = builder;
    }

    public int getNovelId() {
      return novelId;
    }

    public void setNovelId(int novelId) {
      this.novelId = novelId;
    }

    public String getNovelName() {
      return novelName;
    }

    public void setNovelName(String novelName) {
      this.novelName = novelName;
    }

    public NotificationItem(int id, String title, String desc) {
      super(id, title, desc);
      //first
      Log.d(Tag, "NotificationItem[id=" + id + "][title=" + title + "[text=" + desc + "]");
    }

    @Override
    public void show(boolean statusChanged, int status, boolean isShowProgress) {

      String desc = null;
      switch (status) {
        case FileDownloadStatus.pending:  //pause no_cancel
          desc = "准备开始";
          break;
        case FileDownloadStatus.started:  //pause no_cancel
          desc = "准备下载";
          break;
        case FileDownloadStatus.progress: //pause no_cancel
          desc = "正在下载";
          break;
        case FileDownloadStatus.retry: //pause no_cancel
          desc = "正在重试";
          break;
        case FileDownloadStatus.error: //start cancel
          desc = "下载出错";
          break;
        case FileDownloadStatus.paused: //start cancel
          desc = "下载暂停";
          break;
        case FileDownloadStatus.completed: //nothing cancel
          desc = "下载完成";
          break;
        case FileDownloadStatus.warn: //start cancel
          desc = "警告";
          break;
      }
      setDesc(desc);
      if (statusChanged) {
        initNotification();
        builder.setTicker(desc);
        Log.d(Tag, "updateNotification[id=" + getId() + "][title=" + getTitle() + "[text=" + desc + "][status=" + status + "]");
      }
      if (status == FileDownloadStatus.progress) {
        builder.setContentInfo(String.format(getString(R.string.down_progress_text), CommonUtil.convertFileSize(getSofar()), CommonUtil.convertFileSize(getTotal())));
        builder.setProgress(getTotal(), getSofar(), false);
        getNM().notify(getId(), builder.build());
      }
    }

    private void initNotification() {
      int taskId = getId();
      NotificationItem item = notificationHelper.get(taskId);
      NotificationCompat.Builder builder = new NotificationCompat.Builder(FileDownloadHelper.getAppContext());
      item.setBuilder(builder);
      builder.setContentTitle(String.format(getString(R.string.down_name), item.getTitle()))
          .setContentText(item.getDesc());

      int status = item.getStatus();
      if (status == FileDownloadStatus.pending || status == FileDownloadStatus.started
          || status == FileDownloadStatus.progress || status == FileDownloadStatus.retry) {
        Intent pauseIntent = new Intent(KEY_PAUSE);
        pauseIntent.putExtra(EXTRA_ID, taskId);
        builder.addAction(R.drawable.ic_pause, context.getString(R.string.pause),
            PendingIntent.getBroadcast(context, taskId, pauseIntent, PendingIntent.FLAG_UPDATE_CURRENT));
        builder.setAutoCancel(true)
            .setOngoing(false)
            .setSmallIcon(android.R.drawable.stat_sys_download);
      } else if (status == FileDownloadStatus.completed) {
        builder.setAutoCancel(true)
            .setOngoing(false)
            .setSmallIcon(android.R.drawable.stat_sys_download_done);
      } else {
        Intent startIntent = new Intent(KEY_START);
        startIntent.putExtra(EXTRA_ID, taskId);
        builder.addAction(R.drawable.ic_start, context.getString(R.string.start),
            PendingIntent.getBroadcast(context, taskId, startIntent, PendingIntent.FLAG_UPDATE_CURRENT));
        builder.setAutoCancel(true)
            .setOngoing(true)
            .setSmallIcon(android.R.drawable.stat_sys_download_done);
      }
      if (status == FileDownloadStatus.completed) {
        Intent completeIntent = new Intent(KEY_COMPLETE);
        completeIntent.putExtra(EXTRA_ID, taskId);
        builder.addAction(R.drawable.ic_ok, context.getString(R.string.ok),
            PendingIntent.getBroadcast(context, taskId, completeIntent, PendingIntent.FLAG_UPDATE_CURRENT));
      } else {
        Intent removeIntent = new Intent(KEY_REMOVE);
        removeIntent.putExtra(EXTRA_ID, taskId);
        builder.addAction(R.drawable.ic_remove, context.getString(R.string.remove),
            PendingIntent.getBroadcast(context, taskId, removeIntent, PendingIntent.FLAG_UPDATE_CURRENT));
      }
      Log.d(Tag, "show notification[id=" + taskId + "][title=" + item.getTitle() + "[text=" + item.getDesc() + "]");
      getNM().notify(taskId, builder.build());
    }
  }

  public final static String KEY_PAUSE = "com.fenfen.novel.notification.pause";
  public final static String KEY_REMOVE = "com.fenfen.novel.notification.remove";
  public final static String KEY_START = "com.fenfen.novel.notification.start";
  public final static String EXTRA_ID = "com.fenfen.novel.notification.id";
  public final static String KEY_COMPLETE = "com.fenfen.novel.notification.complete";

  private class NotificationListener extends FileDownloadNotificationListener {
    private WeakReference<NovelDownService> wService;

    public NotificationListener(WeakReference<NovelDownService> wService) {
      super(wService.get().notificationHelper);
      this.wService = wService;
    }

    @Override
    protected BaseNotificationItem create(BaseDownloadTask task) {
      NotificationItem item = wService.get().new NotificationItem(task.getId(), (String) task.getTag((Integer) task.getTag()), null);
      item.setNovelId((Integer) task.getTag());
      item.setNovelName((String) task.getTag(item.getNovelId()));
      return item;
    }


    @Override
    protected void completed(BaseDownloadTask task) {
      super.completed(task);
      getHelper().remove(task.getId());
      Log.d(Tag, "completed:" + task.getTag());
      wService.get().handleDownList((Integer) task.getTag());
      if(wService.get().downList != null && wService.get().downList.size() == 0) {
        FileDownloader.getImpl().unBindService();
      }
      NovelDownStatus status = new NovelDownStatus();
      status.setNovelId((Integer) task.getTag());
      status.setDownStatus(CommonUtil.DOWN_STATUS.SUCCESS);
      status.setCreate_time(new Date());
      status.setUpdate_time(new Date());
      NovelDBProvider.getInstance(context).updateDownStatus(status);
    }


    @Override
    public void addNotificationItem(BaseDownloadTask task) {
      super.addNotificationItem(task);
    }

    @Override
    public void destroyNotification(BaseDownloadTask task) {
//      super.destroyNotification(task);
      if (disableNotification(task)) {
        return;
      }

      getHelper().showIndeterminate(task.getId(), task.getStatus());
    }

    @Override
    protected boolean interceptCancel(BaseDownloadTask task,
                                      BaseNotificationItem n) {
      // in this demo, I don't want to cancel the notification, just show for the test
      // so return true
      return true;
    }

    @Override
    protected void pending(BaseDownloadTask task, int soFarBytes, int totalBytes) {
      super.pending(task, soFarBytes, totalBytes);
    }

    @Override
    protected void progress(BaseDownloadTask task, int soFarBytes, int totalBytes) {
      super.progress(task, soFarBytes, totalBytes);
    }

  }

  private void handleDownList(int novelId) {
    for (NovelDownInfo info : downList) {
      if (info.getNovelDownStatus().getNovelId() == novelId) {
        downList.remove(info);
        break;
      }
    }
  }
}
